/**
 * @class   wosh::persistence::qt::EncoderProtocolXmlQt
 * @brief   
 *
 ****************************************************************************
 * @version 0.8.399 $Id: EncoderProtocolXmlQt.h 2759 2010-07-13 14:05:30Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Persistence_Qt_EncoderProtocolXmlQt_H__
 #define __WOSH_Persistence_Qt_EncoderProtocolXmlQt_H__

 #include <framework/persistence/EncoderProtocolXml.h>
 #include <core/ObjectFactory.h>
 #include <QtXml>


using namespace wosh;
namespace wosh {
 class PersistenceDb;
 namespace persistence {
  namespace qt {


#undef WOSH_ENCODER_XML_Qt_CLASS
#define WOSH_ENCODER_XML_Qt_CLASS(CLASSNAME, OBJECT_TYPE)		\
	class CLASSNAME : public wosh::persistence::qt::EncoderBaseXmlQt {														\
		public: virtual inline bool isAbstract() const { return false; }													\
		public: static inline const char* className() { return "wosh::persistence::qt::" #CLASSNAME; }						\
		public: virtual inline const char* getClassName() const { return className(); }										\
		public: static inline const char* mappedObject() { return #OBJECT_TYPE; }											\
		public: virtual inline const char* getMappedObject() const { return mappedObject(); }								\
		public: inline WRESULT serializeTo( const ISerializable* object_s, QDomDocument& doc, QDomElement& contNode, int encoder_options ) {	\
			return CLASSNAME::serializeTo( dynamic_cast<const OBJECT_TYPE*>(object_s), doc, contNode, encoder_options); }						\
		public: inline WRESULT deserializeFrom( ISerializable* object_s, const QDomElement& contNode ) {										\
			return CLASSNAME::deserializeFrom( dynamic_cast<OBJECT_TYPE*>(object_s), contNode); }												\
		public: static WRESULT serializeTo( const OBJECT_TYPE* object, QDomDocument& doc, QDomElement& contNode, int encoder_options );			\
		public: static WRESULT deserializeFrom( OBJECT_TYPE* object, const QDomElement& contNode );												\
		public: CLASSNAME() : EncoderBaseXmlQt() { }																							\
	};


#undef WOSH_ENCODER_XML_Qt_BIND
#define WOSH_ENCODER_XML_Qt_BIND(ENCODER_CLASS, OBJECT_CLASSNAME, VERSION, TMP ) \
	WOSH_ENCODER_BIND(wosh::persistence::qt::EncoderProtocolXmlQt, ENCODER_CLASS, OBJECT_CLASSNAME, VERSION, TMP )


class EncoderBaseXmlQt : public EncoderBaseXml
 {
	WOSH_CLASSNAME(wosh::persistence::qt::EncoderBaseXmlQt)
	WOSH_CLASS_ABSTRACT(true)

	public:
		virtual WRESULT serializeTo( const ISerializable* object, QDomDocument& doc, QDomElement& contNode, int encoder_options ) = 0;
		virtual WRESULT deserializeFrom( ISerializable* object, const QDomElement& contNode ) = 0;

	public:
		virtual int64 serializeTo( const ISerializable* object, char* buffer, int64 buffer_size, int encoder_options );
		virtual int64 deserializeFrom( ISerializable* object, const char* buffer, int64 buffer_size );


	public:
		static void serializeString( const std::string& field, const std::string& value, QDomDocument& doc, QDomElement& contNode, int encoder_options );
		static void serializeLong( const std::string& field, long value, QDomDocument& doc, QDomElement& contNode, int encoder_options );
		static void serializeDouble( const std::string& field, double value, QDomDocument& doc, QDomElement& contNode, int encoder_options );
		static void serializeBool( const std::string& field, bool value, QDomDocument& doc, QDomElement& contNode, int encoder_options );
		static void serializeInt64( const std::string& field, int64 value, QDomDocument& doc, QDomElement& contNode, int encoder_options );
		static void serializeFloat( const std::string& field, float value, QDomDocument& doc, QDomElement& contNode, int encoder_options );

		static void serializeVectorString( const std::vector<std::string>& dataset, QDomDocument& doc, QDomElement& contNode, int encoder_options, const std::string& tagname = "item" );
		static void serializeMapStringLong( const std::map<std::string, long>& dataset, QDomDocument& doc, QDomElement& contNode, int encoder_options, const std::string& tagname = "", const std::string& value_fieldname = "value" );

	public:
		static std::string deserializeString( const std::string& field, const std::string& default_value, const QDomElement& contNode, bool* valid = NULL );
		static long deserializeLong( const std::string& field, long default_value, const QDomElement& contNode, bool* valid = NULL );
		static double deserializeDouble( const std::string& field, double default_value, const QDomElement& contNode, bool* valid = NULL );
		static bool deserializeBool( const std::string& field, bool default_value, const QDomElement& contNode, bool* valid = NULL );
		static int64 deserializeInt64( const std::string& field, int64 default_value, const QDomElement& contNode, bool* valid = NULL );
		static float deserializeFloat( const std::string& field, float default_value, const QDomElement& contNode, bool* valid = NULL );

		static int deserializeVectorString( std::vector<std::string>& dataset, const QDomElement& contNode, const std::string& tagname = "", bool* valid = NULL );
		static int deserializeMapStringLong( std::map<std::string, long>& dataset, const QDomElement& contNode, const std::string& tagname = "", const std::string& value_fieldname = "value", bool* valid = NULL );


	public:

		template <class ObjectType, class EncoderType>
		static WRESULT serializeListT( const typename wosh::ListT<ObjectType*>& dataset, QDomDocument& doc, QDomElement& contNode, int encoder_options ) {
			WRESULT ret = WRET_OK;
			EncoderType encoder;
			dataset.transactionBeginRead();
			EncoderBaseXmlQt::serializeLong( "size", dataset.size(), doc, contNode, EncoderOption_COMPACT );
			typename wosh::ListT<ObjectType*>::ConstIterator it;
			const typename wosh::ListT<ObjectType*>::ConstIterator it_end = dataset.end();
			for ( it=dataset.begin(); it!=it_end; ++it ) {
				QDomElement itemNode = doc.createElement("item"); contNode.appendChild(itemNode);
				if ( *it == NULL ) continue;
				ret += encoder.serializeTo( *it, doc, itemNode, encoder_options );
			 }
			dataset.transactionEnd();
			return ret;
		 }

		template <class ObjectType, class EncoderType>
		static WRESULT deserializeListT( typename wosh::ListT<ObjectType*>& dataset, const QDomElement& contNode ) {
			WRESULT ret = WRET_OK; WRESULT ret_t = WRET_OK;
			EncoderType encoder;
			dataset.transactionBeginWrite();
			QDomNodeList nodesList = contNode.childNodes();
			for( unsigned int j=0; j<nodesList.length(); ++j ) {
				QDomElement childNode = nodesList.item(j).toElement();
				ObjectType* object = ObjectFactory::createTypeOf<ObjectType>(false);
				if ( object == NULL ) {
					dataset.push_back(NULL);
					continue;
				 }
				ret_t = encoder.deserializeFrom( object, childNode );
				if ( WSUCCEEDED(ret_t) )
					dataset.push_back(object);
				else {
					dataset.push_back(NULL);
					ret += WRET_ERR_PARAM;
				 }
			 }
			dataset.transactionEnd();
			return ret;
		 }
/*
		template <typename ObjectKeyType, class ObjectValueType, class EncoderValueType>
		static WRESULT serializeMapT( const typename wosh::MapT<ObjectKeyType,ObjectValueType*>& dataset, QDomDocument& doc, QDomElement& contNode, int encoder_options ) {
			WRESULT ret = WRET_OK;
			EncoderXml_Qt_Variant encoderKey;
			EncoderValueType encoderValue;
			dataset.transactionBeginRead();
			EncoderBaseXmlQt::serializeLong( "size", dataset.size(), doc, contNode, EncoderOption_COMPACT );
			typename wosh::MapT<ObjectKeyType,ObjectValueType*>::ConstIterator it;
			const typename wosh::MapT<ObjectKeyType,ObjectValueType*>::ConstIterator it_end = dataset.end();
			for ( it=dataset.begin(); it!=it_end; ++it ) {
				QDomElement itemNode = doc.createElement("item"); contNode.appendChild(itemNode);
				QDomElement keyNode = doc.createElement("key"); itemNode.appendChild(keyNode);
				ret += encoderKey.serializeTo( &Variant(it->first), doc, keyNode, encoder_options );
				if ( it->second == NULL ) continue;
				QDomElement valueNode = doc.createElement("value"); itemNode.appendChild(valueNode);
				ret += encoderValue.serializeTo( it->second, doc, valueNode, encoder_options );
			 }
			dataset.transactionEnd();
			return ret;
		 }
*/
		template <class ObjectKeyType, typename ObjectValueType, class EncoderKeyType, class EncoderValueType>
		static WRESULT serializeMapT( const typename wosh::MapT<ObjectKeyType*,ObjectValueType>& dataset, QDomDocument& doc, QDomElement& contNode, int encoder_options ) {
			WRESULT ret = WRET_OK;
			EncoderKeyType encoderKey;
			EncoderValueType encoderValue;
			dataset.transactionBeginRead();
			EncoderBaseXmlQt::serializeLong( "size", dataset.size(), doc, contNode, EncoderOption_COMPACT );
			typename wosh::MapT<ObjectKeyType*,ObjectValueType>::ConstIterator it;
			const typename wosh::MapT<ObjectKeyType*,ObjectValueType>::ConstIterator it_end = dataset.end();
			for ( it=dataset.begin(); it!=it_end; ++it ) {
				QDomElement itemNode = doc.createElement("item"); contNode.appendChild(itemNode);
				QDomElement valueNode = doc.createElement("value"); itemNode.appendChild(valueNode);
				Variant vKey(it->first);
				ret += encoderValue.serializeTo( &vKey, doc, valueNode, EncoderOption_COMPACT );
				if ( it->first == NULL ) continue;
				QDomElement keyNode = doc.createElement("key"); itemNode.appendChild(keyNode);
				ret += encoderKey.serializeTo( &vKey, doc, keyNode, encoder_options );
			 }
			dataset.transactionEnd();
			return ret;
		 }

		template <class ObjectKeyType, typename ObjectValueType, class EncoderKeyType, class EncoderValueType>
		static WRESULT deserializeMapT( typename wosh::MapT<ObjectKeyType*,ObjectValueType>& dataset, const QDomElement& contNode, ObjectValueType default_value ) {
			WRESULT ret = WRET_OK; WRESULT ret_t = WRET_OK;
			EncoderKeyType encoderKey;
			EncoderValueType encoderValue; Variant vValue;
			dataset.transactionBeginWrite();
			QDomNodeList nodesList = contNode.childNodes();
			for( unsigned int j=0; j<nodesList.length(); ++j ) {
				QDomElement childNode = nodesList.item(j).toElement();
				QDomElement node_value = childNode.namedItem("value").toElement();
				ret += encoderValue.deserializeFrom( &vValue, node_value );
				ObjectValueType value = vValue.to<ObjectValueType>(default_value);
				QDomElement node_key = childNode.namedItem("key").toElement();
				ObjectKeyType* object = ObjectFactory::createTypeOf<ObjectKeyType>(true);
				if ( object == NULL ) {
					dataset.set(NULL, value);
					continue;
				 }
				ret_t = encoderKey.deserializeFrom( object, node_key );
				if ( WSUCCEEDED(ret_t) )
					dataset.set(object, value);
				else {
					dataset.set(NULL, value);
					ObjectFactory::destroy(object);
					ret += WRET_ERR_PARAM;
				 }
			 }
			dataset.transactionEnd();
			return ret;
		 }


	public:
		EncoderBaseXmlQt() : EncoderBaseXml() { }
		virtual ~EncoderBaseXmlQt() { }

};


// ------------------------------------------------------------------------------------------------------------------------


class PersistenceDbXmlQt;

class EncoderProtocolXmlQt : public EncoderProtocolXml
 {
	WOSH_ENCODERPROTOCOL(wosh::persistence::qt::EncoderProtocolXmlQt)

	public:
		EncoderProtocolXmlQt();
		virtual ~EncoderProtocolXmlQt() { }

	public:
		const char* getProtocol() const		{ return "XML::QT"; }
		double getProtocolVersion() const	{ return 0.0; }

		PersistenceDb* createDb() const;


	public:
		WRESULT loadObjects( std::vector<ISerializable*>& objects, const std::string& parameters );

		WRESULT saveObject( const ISerializable* object, const std::string& parameters );
		WRESULT saveObjects( const std::vector<ISerializable*>& objects, const std::string& parameters );

	public:
		static WRESULT serializeTo( const ISerializable* object, QDomDocument& doc, QDomElement& contNode, int encoder_options );
		static WRESULT deserializeFrom( ISerializable* object, const QDomElement& contNode );
		static ISerializable* deserializeFrom( const QDomElement& contNode, WRESULT* return_code = NULL );


//		virtual WRESULT serializeTo( const PersistenceDb* object );

		template <class DYNAMIC_CAST>
		static inline DYNAMIC_CAST* deserializeFrom( const QDomElement& contNode, WRESULT* return_code = NULL ) {
			return dynamic_cast<DYNAMIC_CAST*>( deserializeFrom(contNode, return_code) );
		 }

	protected:
		WRESULT loadXmlDocument( QDomDocument& doc, const std::string& filename );
		WRESULT saveXmlDocument( QDomDocument& doc, const std::string& filename );


}; // class def



  }; // namespace qt
 }; // namespace persistence
}; // namespace wosh

#endif //__WOSH_Persistence_Qt_EncoderProtocolXmlQt_H__
